﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Document;
using System.IO;

namespace LuaVM.Controls
{
    public partial class LuaEditBox : UserControl
    {
        public delegate void DocumentChangedDelegate(bool modified, string filePath);

        /// <summary>
        /// 属性：文本内容直接访问
        /// </summary>        
        public override string Text
        {
            get
            {
                return textEditorControl1.Text;
            }

            set
            {
                textEditorControl1.Text = value;
            }
        }

        /// <summary>
        /// 文档内容是否已更改
        /// </summary>
        public bool Modified { get; set; }
        
        /// <summary>
        /// 控件内容是否只读
        /// </summary>
        public bool ReadOnly
        {
            get
            {
                return textEditorControl1.ReadOnly;
            }

            set
            {
                textEditorControl1.ReadOnly = value;
            }
        }

        /// <summary>
        /// 是否可以undo
        /// </summary>
        public bool CanUndo => textEditorControl1.EnableUndo;

        /// <summary>
        /// 是否可以redo
        /// </summary>
        public bool CanRedo => textEditorControl1.EnableRedo;

        /// <summary>
        /// 是否有文字被选中(可以cut/copy)
        /// </summary>
        public bool HasSomethingSelected => textEditorControl1.ActiveTextAreaControl.SelectionManager.HasSomethingSelected;

        /// <summary>
        /// 是否可以粘贴
        /// </summary>
        public bool CanPaste => textEditorControl1.ActiveTextAreaControl.TextArea.ClipboardHandler.EnablePaste;

        /// <summary>
        /// 控件字体
        /// </summary>
        public override Font Font
        {
            get
            {
                return base.Font;
            }

            set
            {
                base.Font = value;
                textEditorControl1.Font = value;
            }
        }

        /// <summary>
        /// 当前打开的文件名
        /// </summary>
        public string FileName
        {
            get
            {
                string name = textEditorControl1.FileName;
                if (name == "")
                {
                    return null;
                }

                return name;
            }

            set
            {
                textEditorControl1.FileName = value;
            }
        }

        public LuaSyntaxManager Syntax { get; private set; }

        /// <summary>
        /// 菜单项本地化
        /// </summary>
        public Dictionary<string, string> ContextMenuTexts { get => textEditorControl1.ActiveTextAreaControl.ContextMenuTexts; set => textEditorControl1.ActiveTextAreaControl.ContextMenuTexts = value; }

        /// <summary>
        /// 控件文档属性发生变化
        /// </summary>
        public DocumentChangedDelegate DocumentChanged;

        private string m_lastSavedText = "";
        private Dictionary<string, FileSyntaxModeProvider> m_providers = new Dictionary<string, FileSyntaxModeProvider>();

        public LuaEditBox()
        {
            InitializeComponent();

            textEditorControl1.IndentStyle = IndentStyle.Smart;
            textEditorControl1.AllowCaretBeyondEOL = false;
            textEditorControl1.ShowHRuler = false;
            textEditorControl1.ShowVRuler = false;
            textEditorControl1.TextChanged += TextEditor_TextChanged;
            textEditorControl1.Document.FoldingManager.FoldingStrategy = new LuaFoldingStrategy();

            ContextMenuTexts = new Dictionary<string, string>() {
                { "Undo", "撤销" },
                { "Redo", "重做" },
                { "Cut", "剪切" },
                { "Copy", "复制" },
                { "Paste", "粘贴" },
                { "Delete", "删除" },
                { "Select All", "全选" },
            };

            Syntax = new LuaSyntaxManager(Properties.Resources.SyntaxHighlight);
            SetHighlightingFolder(Constants.UserFolder);
            SetHighlighting(Constants.SyntaxName);
        }

        /// <summary>
        /// 设置语法高亮规则文件(*.xshd)所在目录
        /// </summary>
        /// <param name="folder">目录路径</param>
        public void SetHighlightingFolder(string folder)
        {
            if (string.IsNullOrEmpty(folder) || !Directory.Exists(folder))
            {
                throw new DirectoryNotFoundException(folder);
            }

            folder = folder.ToLower();
            if (!m_providers.ContainsKey(folder))
            {
                FileSyntaxModeProvider provider = new FileSyntaxModeProvider(folder);
                HighlightingManager.Manager.AddSyntaxModeFileProvider(provider);
                m_providers.Add(folder, provider);
            }
        }

        /// <summary>
        /// 设置高亮规则
        /// </summary>
        /// <param name="name">规则名</param>
        public void SetHighlighting(string name)
        {
            textEditorControl1.SetHighlighting(name);
        }

        /// <summary>
        /// 重新载入语法高亮内容
        /// </summary>
        public void ReloadHighlighting()
        {
            HighlightingManager.Manager.ReloadSyntaxModes();
        }

        /// <summary>
        /// 设置焦点
        /// </summary>
		public new void Focus()
        {
            textEditorControl1.Focus();
        }

        /// <summary>
        /// 在文档内容存在改变的情况下执行特定操作前提示用户存盘
        /// </summary>
        /// <param name="ignoreNullFile"></param>
        /// <returns></returns>
        public bool PromptForSave(bool ignoreNullFile = false)
        {
            if (!Modified)
            {
                return true;
            }

            if (ignoreNullFile && FileName == null)
            {
                return true;
            }

            DialogResult result = MessageBox.Show("文档内容已更改，是否在继续操作前先保存？", "保存更改", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (result == DialogResult.Cancel)
            {
                return false;
            }

            if (result == DialogResult.No)
            {
                return true;
            }

            string filePath = FileName;
            if (filePath == null)
            {
                SaveFileDialog dlg = new SaveFileDialog();
                dlg.DefaultExt = ".lua";
                dlg.AddExtension = true;
                if (dlg.ShowDialog(this) != DialogResult.OK)
                {
                    return false;
                }

                filePath = dlg.FileName;
            }

            return SaveFileAs(filePath);
        }

        /// <summary>
        /// 创建新文件
        /// </summary>
        /// <returns>是否成功</returns>
        public bool NewFile()
        {
            if (!PromptForSave())
            {
                return false;
            }

            Text = Properties.Resources.NewScript;
            m_lastSavedText = Text;
            textEditorControl1.Visible = false;
            textEditorControl1.Visible = true;
            textEditorControl1.Focus();
            FileName = null;
            Modified = false;
            DocumentChanged?.Invoke(Modified, FileName);
            Focus();
            return true;
        }

        public bool LoadFile()
        {
            if (!PromptForSave())
            {
                return false;
            }

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.CheckFileExists = true;
            dlg.Filter = "Lua脚本(*.lua)|*.lua|所有文件(*.*)|*.*";

            if (dlg.ShowDialog(this) != DialogResult.OK)
            {
                return false;
            }

            return LoadFile(dlg.FileName);
        }

        /// <summary>
        /// 载入文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>是否成功</returns>
        public bool LoadFile(string filePath)
        {
            try
            {
                textEditorControl1.LoadFile(filePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }

            FileName = filePath;
            Modified = false;
            m_lastSavedText = Text;
            DocumentChanged?.Invoke(Modified, FileName);
            Focus();
            return true;
        }

        /// <summary>
        /// 保存当前文件
        /// </summary>
        /// <returns>是否成功</returns>
        public bool SaveFile()
        {
            if (string.IsNullOrEmpty(FileName))
            {
                return false;
            }

            try
            {
                textEditorControl1.SaveFile(FileName);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }

            m_lastSavedText = Text;
            Modified = false;
            DocumentChanged?.Invoke(Modified, FileName);
            Focus();
            return true;
        }

        public void LoadTemp()
		{
            string text = null;
            try
            {
                text = File.ReadAllText(Constants.TempSaveFile);
            }
            catch
            {
            }

            if (string.IsNullOrEmpty(text))
			{
                text = Properties.Resources.NewScript;                
            }

            Text = text;
            m_lastSavedText = text;
            Modified = false;
            FileName = null;
            DocumentChanged?.Invoke(Modified, FileName);
            Focus();
        }

        public void SaveTemp()
		{
            try
            {
                File.WriteAllText(Constants.TempSaveFile, textEditorControl1.Text);
            }
            catch
            {
            }
        }

        public bool SaveFileAs()
		{
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.DefaultExt = ".lua";
            dlg.AddExtension = true;
            if (dlg.ShowDialog(this) != DialogResult.OK)
            {
                return false;
            }

            return SaveFileAs(dlg.FileName);
        }

        /// <summary>
        /// 文件另存为
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns>是否成功</returns>
        public bool SaveFileAs(string filePath)
        {
            try
            {
                textEditorControl1.SaveFile(filePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }

            m_lastSavedText = Text;
            Modified = false;
            FileName = filePath;
            DocumentChanged?.Invoke(Modified, FileName);
            Focus();
            return true;
        }        

        /// <summary>
        /// 剪切
        /// </summary>
        public void Cut()
        {
            if (!ReadOnly)
            {
                textEditorControl1.ActiveTextAreaControl.TextArea.ClipboardHandler.Cut(null, null);
            }
        }

        /// <summary>
        /// 复制
        /// </summary>
        public void Copy()
        {
            textEditorControl1.ActiveTextAreaControl.TextArea.ClipboardHandler.Copy(null, null);
        }

        /// <summary>
        /// 粘贴
        /// </summary>
        public void Paste()
        {
            if (!ReadOnly)
            {
                textEditorControl1.ActiveTextAreaControl.TextArea.ClipboardHandler.Paste(null, null);
            }
        }

        /// <summary>
        /// 删除选中文字
        /// </summary>
        public void Delete()
        {
            if (!ReadOnly && HasSomethingSelected)
            {
                new ICSharpCode.TextEditor.Actions.Delete().Execute(textEditorControl1.ActiveTextAreaControl.TextArea);
                textEditorControl1.ActiveTextAreaControl.TextArea.Focus();
            }
        }

        /// <summary>
        /// 全选
        /// </summary>
        public void SelectAll()
        {
            new ICSharpCode.TextEditor.Actions.SelectWholeDocument().Execute(textEditorControl1.ActiveTextAreaControl.TextArea);
            textEditorControl1.ActiveTextAreaControl.TextArea.Focus();
        }

        /// <summary>
        /// 执行undo
        /// </summary>
        public void Undo()
        {
            textEditorControl1.Undo();
        }

        /// <summary>
        /// 执行redo
        /// </summary>
        public void Redo()
        {
            textEditorControl1.Redo();
        }

        private void TextEditor_TextChanged(object sender, EventArgs e)
        {
            textEditorControl1.Document.FoldingManager.UpdateFoldings(null, null);
            bool m = m_lastSavedText != textEditorControl1.Text;
            if (Modified != m)
			{
                Modified = m;
                DocumentChanged?.Invoke(Modified, FileName);
            }
        }
    }
}
